"""
https://leetcode.cn/problems/min-stack/description/

155. 最小栈
已解答
中等
相关标签
premium lock icon
相关企业
提示
设计一个支持 push ，pop ，top 操作，并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
 

示例 1:

输入：
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出：
[null,null,null,null,-3,null,0,-2]

解释：
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.
 

提示：

-231 <= val <= 231 - 1
pop、top 和 getMin 操作总是在 非空栈 上调用
push, pop, top, and getMin最多被调用 3 * 104 次

"""

class MinStack:

    """
    核心需求，是要在常数时间内，检索到最小元素。
    因此需要维护一个从大到小排列的栈。
    

    """

    def __init__(self):
        self.data=[]
        # 维护最小索引列表（查找数据可以二分）
        self.min_idxs=[]
        pass
        
    def find_lt_idx(self,val):
        if not self.min_idxs:
            return -1
        if val<self.data[self.min_idxs[0]]:
            return -1
        if self.data[self.min_idxs[-1]]<=val:
            return len(self.min_idxs)-1
        # 左右均闭
        left=0
        right=len(self.min_idxs)-1
        while left+1<right:
            mid=(left+right)//2
            if self.data[self.min_idxs[mid]]==val:
                return mid
            if val<self.data[self.min_idxs[mid]]:
                right=mid
            else:
                left=mid
        return left

    def push(self, val: int) -> None:
        new_idx=len(self.data)
        self.data.append(val)

        lt_idx=self.find_lt_idx(val)
        self.min_idxs.insert(lt_idx+1,new_idx)
    
        pass
        

    def pop(self) -> None:
        pop_idx=len(self.data)-1
        self.data.pop()

        rm_idx=self.min_idxs.index(pop_idx)
        del self.min_idxs[rm_idx]
        
        pass

    def top(self) -> int:
        return self.data[-1]
        pass

    def getMin(self) -> int:
        return self.data[self.min_idxs[0]]
        pass

if __name__=='__main__':
    minStack =  MinStack();
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    v1=minStack.getMin();   #--> 返回 -3.
    print(v1)
    minStack.pop();
    v2=minStack.top();      #--> 返回 0.
    print(v2)
    v3=minStack.getMin();   #--> 返回 -2.
    print(v3)